package math2;

/**
 * Serendipity ansatz function on Q8 element. Refer to Meschke, FEM lecture
 * note, section 4.5
 * 
 * @author hbui
 * 
 */
public class SerendipityFBOnQ8 extends PolynomialBasisOnRnToR {

	public SerendipityFBOnQ8() {

		addBasisFunction(
		/*
		 * N1 = -1/4(1-xi[0])(1-xi[1])(1+xi[0]+xi[1])
		 */
		new FunctionRnToR() {

			@Override
			public double valueAt(double... xi) {
				return -(1 - xi[0]) * (1 - xi[1]) * (1 + xi[0] + xi[1]) / 4;
			}

			@Override
			public double[] gradientAt(double... xi) {
				return new double[] { (1 - xi[1]) * (2 * xi[0] + xi[1]) / 4,
						(1 - xi[0]) * (xi[0] + 2 * xi[1]) / 4 };
			}
		},
		/*
		 * N2 = -1/4(1+xi[0])(1-xi[1])(1-xi[0]+xi[1])
		 */
		new FunctionRnToR() {

			@Override
			public double valueAt(double... xi) {
				return -(1 + xi[0]) * (1 - xi[1]) * (1 - xi[0] + xi[1]) / 4;
			}

			@Override
			public double[] gradientAt(double... xi) {
				return new double[] { (1 - xi[1]) * (2 * xi[0] - xi[1]) / 4,
						(1 + xi[0]) * (-xi[0] + 2 * xi[1]) / 4 };
			}
		},
		/*
		 * N3 = -1/4(1+xi[0])(1+xi[1])(1-xi[0]-xi[1])
		 */
		new FunctionRnToR() {

			@Override
			public double valueAt(double... xi) {
				return -(1 + xi[0]) * (1 + xi[1]) * (1 - xi[0] - xi[1]) / 4;
			}

			@Override
			public double[] gradientAt(double... xi) {
				return new double[] { (1 + xi[1]) * (2 * xi[0] + xi[1]) / 4,
						(1 + xi[0]) * (xi[0] + 2 * xi[1]) / 4 };
			}
		},
		/*
		 * N4 = -1/4(1-xi[0])(1+xi[1])(1+xi[0]-xi[1])
		 */
		new FunctionRnToR() {

			@Override
			public double valueAt(double... xi) {
				return -(1 - xi[0]) * (1 + xi[1]) * (1 + xi[0] - xi[1]) / 4;
			}

			@Override
			public double[] gradientAt(double... xi) {
				return new double[] { (1 + xi[1]) * (2 * xi[0] - xi[1]) / 4,
						(1 - xi[0]) * (-xi[0] + 2 * xi[1]) / 4 };
			}
		},
		/*
		 * N5 = 1/2(1-xi[0]^2)(1-xi[1])
		 */
		new FunctionRnToR() {

			@Override
			public double valueAt(double... xi) {
				return (1 - xi[0] * xi[0]) * (1 - xi[1]) / 2;
			}

			@Override
			public double[] gradientAt(double... xi) {
				return new double[] { -xi[0] * (1 - xi[1]), -(1 - xi[0] * xi[0]) / 2 };
			}
		},
		/*
		 * N6 = 1/2(1+xi[0])(1-xi[1]^2)
		 */
		new FunctionRnToR() {

			@Override
			public double valueAt(double... xi) {
				return (1 + xi[0]) * (1 - xi[1] * xi[1]) / 2;
			}

			@Override
			public double[] gradientAt(double... xi) {
				return new double[] { (1 - xi[1] * xi[1]) / 2, -(1 + xi[0]) * xi[1] };
			}
		},
		/*
		 * N7 = 1/2(1-xi[0]^2)(1+xi[1])
		 */
		new FunctionRnToR() {

			@Override
			public double valueAt(double... xi) {
				return (1 - xi[0] * xi[0]) * (1 + xi[1]) / 2;
			}

			@Override
			public double[] gradientAt(double... xi) {
				return new double[] { -xi[0] * (1 + xi[1]), (1 - xi[0] * xi[0]) / 2 };
			}
		},
		/*
		 * N8 = 1/2(1-xi[0])(1-xi[1]*xi[1])
		 */
		new FunctionRnToR() {

			@Override
			public double valueAt(double... xi) {
				return (1 - xi[0]) * (1 - xi[1] * xi[1]) / 2;
			}

			@Override
			public double[] gradientAt(double... xi) {
				return new double[] { -(1 - xi[1] * xi[1]) / 2, -(1 - xi[0]) * xi[1] };
			}
		});
	}

	@Override
	public int getP() {
		return 3;
	}

	@Override
	public void setP(int p) {
	}

	@Override
	public Object clone() {
		return new SerendipityFBOnQ8();
	}
}
